package project;

import java.util.LinkedList;

public class fairshare {

	private int clk;
	LinkedList<process> allProcesses = new LinkedList<process>();
	LinkedList<user> users = new LinkedList<user>();
	LinkedList<user> usersInClk = new LinkedList<user>();
	boolean inQuantum = false;

	public int getClk() {
		return clk;
	}

	public void setClk(int clk) {
		this.clk = clk;
	}

	public LinkedList<process> getAllProcesses() {
		return allProcesses;
	}

	public void setAllProcesses(LinkedList<process> allProcesses) {
		this.allProcesses = allProcesses;
	}

	public LinkedList<user> getUsers() {
		return users;
	}

	public void setUsers(LinkedList<user> users) {
		this.users = users;
	}

	public LinkedList<user> getUsersInClk() {
		return usersInClk;
	}

	public void setUsersInClk(LinkedList<user> usersInClk) {
		this.usersInClk = usersInClk;
	}

	public fairshare(int clk) {
		super();
		this.clk = clk;
	}

	public static void main(String args[]) {
		fairshare f = new fairshare(0);


		LinkedList<process> user1List = new LinkedList<process>();
		LinkedList<process> user2List = new LinkedList<process>();

		process p1 = new process("p1", 0, 4, "user1");
		user1List.add(p1);

		process p2 = new process("p2", 0, 2, "user2");
		user2List.add(p2);
		process p3 = new process("p3", 0, 2, "user2");
		user2List.add(p3);

		user user1 = new user("user1", user1List, 1);
		user user2 = new user("user2", user2List, 10);

		f.getUsers().addLast(user1);
		f.getUsers().addLast(user2);

		f.addingProcess();
		f.run();
	}

	public void addingProcess() {

		for (int i = 0; i < getUsers().size(); i++) {
			for (int j = 0; j < getUsers().get(i).getUserProcesses().size(); j++) {
				if (getUsers().get(i).getUserProcesses().get(j)
						.getArrival_time() == getClk()&&! getUsersInClk().contains(getUsers().get(i))) {
					getUsersInClk().addLast(getUsers().get(i));
				}
			}
		}
	}

	
	public void run()
	{
		
		if (getClk() > getSum())
			return;
		//part1
		if(getUsersInClk().isEmpty())
		{
			setClk(getClk() + 1);
			System.out.println("time is now in part1 " + getClk());
			addingProcess();
			run();
		}
		else 
		{
			for (int i = 0; i < getUsersInClk().size(); i++) 
			{
				int prio = getUsersInClk().get(i).getUserPriority();
				for (int k = 0; k < prio; k++)
				{

					if (prio - k >= 2) 
					{
						k = k + 1;
						if (!getUsersInClk().get(i).getUserProcesses()
								.isEmpty()) 
						{
							roundrobin(getUsersInClk().get(i)
									.getUserProcesses());
						}
						else 
						{
							getUsersInClk().remove(i);
							i--;
						}
					}
					else
					{
						if (prio - k == 1) 
						{
							if (!getUsersInClk().get(i).getUserProcesses()
									.isEmpty()) 
							{
								runOnce(getUsersInClk().get(i)
										.getUserProcesses());
							}
							else 
							{
								getUsersInClk().remove(i);
								i--;
							}
						}
					}

				}
			} run();
			
		}
	}	

	public void roundrobin(LinkedList<process> p)
	{
		System.out.println("in rr " + p.getFirst().getArrival_time());
		while (p.getFirst().getArrival_time() > getClk()) 
		{
			p.addLast(p.getFirst());
		}
		if (p.getFirst().getRun_time() >= 2) 
		{
			System.out.println("running a process " + p.getFirst().getName());
			p.addLast(p.getFirst());
			setClk(getClk() + 1);
			System.out.println("time is " + getClk());
			p.getLast().setRun_time(p.getLast().getRun_time() - 1);
			addingProcess();
			// second time
			System.out.println("running a process " + p.getFirst().getName());
			p.addLast(p.getFirst());
			setClk(getClk() + 1);
			System.out.println("time is " + getClk());
			p.getLast().setRun_time(p.getLast().getRun_time() - 1);
			
			if (p.getLast().getRun_time() == 0) 
			{
				p.removeLast();
			}
			addingProcess();
			
		}
		else
		{
			if (p.getFirst().getRun_time() == 1) 
			{
				System.out.println(" in else");
				System.out.println("running " + p.getFirst().getName());
				p.addLast(p.getFirst());
				setClk(getClk() + 1);
				System.out.println("time is " + getClk());
				p.getLast().setRun_time(p.getLast().getRun_time() - 1);
				addingProcess();
			}
		}
		if(p.getLast().getRun_time()==0)
		{
			p.removeLast();
		}
		if (p.getFirst().getRun_time() == 0) 
		{
			p.removeFirst();
		}
	}
	

	public void runOnce(LinkedList<process> p) 
	{
		if (p.getFirst().getRun_time() == 0)
		{
			p.removeFirst();
		} 
		else
		{
			System.out.println("runOnce " + p.getFirst().getName());
			p.addLast(p.getFirst());
			setClk(getClk() + 1);
			System.out.println("time is " + getClk());
			p.getLast().setRun_time(p.getLast().getRun_time() - 1);
			addingProcess();
			if (p.getLast().getRun_time() == 0) 
			{
				p.removeLast();
			}
		}
	}

	/**
	 * 
	 * @return an int that indicates the total remaining time 
	 * for the run-times of current processes
	 */
	public int getSum()
	{
		int sum = 0;
		for (int i = 0; i < getUsers().size(); i++)
		{
			for (int j = 0; j < getUsers().get(i).getUserProcesses().size(); j++)
			{
				sum = sum
						+ getUsers().get(i).getUserProcesses().get(j)
								.getRun_time();
			}
		}
		return sum;
	}
}